#include "byte.h"

int sys_trim(const char* inbuf, ushort inlen, char* &start)
{
    start = (char*)inbuf;

    if(0 == *inbuf) return 0;

    char* end = (char*)inbuf + inlen;

    while(start < end)
    {
        if((uchar)*start > 0x20)
            break;
        else if(0 == *start)
            return 0;
        else
            ++start;
    }

    while(start < end)
    {
        --end;

        if((uchar)*end > 0x20)
        {
            ++end;
            break;
        }
    }

    return (int)(end - start);
}

CByteBuffer::CByteBuffer(const char* ownername)
: m_rpos(0)
, m_wpos(0)
, m_ownername(ownername)
{
    m_data.resize(1); m_data[0] = '\0';
}

CByteBuffer::CByteBuffer(const char* inbuf, ushort inlen, const char* ownername)
: m_rpos(0)
, m_wpos(0)
, m_ownername(ownername)
{
    Write(inbuf, inlen);
}

bool CByteBuffer::Read(char* outbuf, ushort outlen)
{
    if(NULL == outbuf || 0 == outlen) return false;

    if((ushort)(m_rpos + outlen) >= m_data.size()) return false;

    memcpy(outbuf, &m_data[m_rpos], outlen); m_rpos += outlen;

    return true;
}

bool CByteBuffer::Write(const char* inbuf, ushort inlen)
{
    if(NULL == inbuf || 0 == inlen) return false;

    if(m_data.size() <= (ushort)(m_wpos + inlen))
    {
        m_data.resize(m_wpos+inlen+1); m_data[m_wpos+inlen] = '\0';
    }

    memcpy(&m_data[m_wpos], inbuf, inlen); m_wpos += inlen;

    return true;
}

static int GetString(CByteBuffer& buffer, string& outbuf, ushort& outlen)
{
    char* s = new char[outlen];
    
    if(NULL == s) return 0;

    if(!buffer.Read(s, outlen))
    {
        delete[] (s); return -1;
    }
 
    outbuf.append(s, outlen); delete[] (s);

    return outlen;
}

int CByteBuffer::ToBlock(CByteBlock* block)
{
    if(!Read((*block).m_blocksign)) return -1;

    ushort size;

    if(!Read(size)) return -1;

    (*block).m_blockname = "";
    
    if(0 != size)
    {
        if(GetString(*this, (*block).m_blockname, size) <= 0)
            return size;
    }

    if(!Read(size)) return -1;

    (*block).m_blockvalue = "";
    
    if(0 != size)
    {
        if(GetString(*this, (*block).m_blockname, size) <= 0)
            return size;
    }

    if(!Read(size)) return -1;

    if(0 != size)
    {
        string s;
        
        if(GetString(*this, (*block).m_blockname, size) <= 0) return size;

        CByteBuffer buffer(s.c_str(), s.size());

        while(buffer.m_rpos < buffer.m_wpos)
        {
            CByteBlock* child = AddChild<CByteBlock>(block, BYTE_SIGN_NODE);

            if(NULL == child) return 0;
            else return buffer.ToBlock(child);
        }
    }

    return 1;
}

CByteBlock::CByteBlock(const char* ownername)
: m_blocksign(0)
, m_parent(NULL)
, m_seperator("@@")
, m_ownername(ownername)
{
}

CByteBlock::CByteBlock(uchar sign, CByteBlock* parent)
: m_blocksign(sign)
, m_parent(parent)
, m_seperator("@@")
{
}

CByteBlock::~CByteBlock()
{
    for(vector<CByteBlock*>::iterator it = m_children.begin(); it != m_children.end(); ++it)
    {
        delete (*it);
    }

    m_children.clear();
}

bool CByteBlock::IsEmpty()
{
    return m_children.empty() && m_blockname.empty() && m_blockvalue.empty();
}

CByteBlock* CByteBlock::GetParent()
{
    return m_parent;
}

int CByteBlock::GetChildCount(uchar sign, const char* name)
{
    int count = 0;

    BlockIterator it = m_children.begin();

    while(it != m_children.end())
    {
        if((*it)->GetBlockSign() == sign && (*it)->GetBlockName() == name)
            ++count;

        ++it;
    }

    return count;
}

CByteBlock* CByteBlock::GetNextChild(uchar index)
{
    BlockIterator it = m_children.begin();

    while(it != m_children.end())
    {
        if(--index == 0) return (*it);

        ++it;
    }

    return NULL;
}

CByteBlock* CByteBlock::FindChild(uchar sign, uchar index)
{
    BlockIterator it = m_children.begin();

    while(it != m_children.end())
    {
        if((*it)->GetBlockSign() == sign)
        {
            if(--index == 0) return (*it);
        }

        ++it;
    }

    return NULL;
}

CByteBlock* CByteBlock::FindChild(uchar sign, const char* name, uchar index)
{
    BlockIterator it = m_children.begin();

    while(it != m_children.end())
    {
        if((*it)->GetBlockSign() == sign && (*it)->GetBlockName() == name)
        {
            if(--index == 0) return (*it);
        }

        ++it;
    }

    return NULL;
}


int CByteBlock::SetBlockName(string name)
{
    return SetBlockName(name.c_str(), name.size());
}

int CByteBlock::SetBlockName(const char* name, ushort namelen)
{
    char *start;

    int len = sys_trim(name, namelen, start);

    if(len > 0)
        m_blockname.append(start, len);

    return len;
}

int CByteBlock::SetBlockValue(string value)
{
    return SetBlockValue(value.c_str(), value.size());
}

int CByteBlock::SetBlockValue(const char* value, ushort valuelen)
{
    char *start;

    int len = sys_trim(value, valuelen, start);

    if(len > 0)
    {
        if(!m_blockvalue.empty() && !m_seperator.empty())
            m_blockvalue += m_seperator;
        m_blockvalue.append(start, len);
    }

    return len;
}

int CByteBlock::ToBuffer(CByteBuffer* outbuffer)
{
    if(IsEmpty()) return -1;

    CByteBuffer buffer;

    buffer.Write(m_blocksign);

    ushort size = m_blockname.size(); buffer.Write(size);

    if(0 != size) buffer.Write(m_blockname.c_str(), size);

    size = m_blockvalue.size(); buffer.Write(size);

    if(0 != size) buffer.Write(m_blockvalue.c_str(), size);

    CByteBuffer blockbuffer;

    for(BlockIterator it = m_children.begin(); it != m_children.end(); ++it)
    {
        CByteBlock* child = *it;

        if(child->ToBuffer(&blockbuffer) < 0)
            return -1;
    }

    size = blockbuffer.GetSize(); buffer.Write(size);

    if(0 != size) buffer.Write(blockbuffer.GetByte(), size);

    outbuffer->Write(buffer.GetSize());

    outbuffer->Write(buffer.GetByte(), buffer.GetSize());

    return 1;
}

bool en_byte_node(CByteBlock& root, string name, string value)
{
    CByteBlock* block = AddChild<CByteBlock>(&root, BYTE_SIGN_NODE);

    if(NULL == block) return false;

    block->SetBlockName(name); block->SetBlockValue(value);

    return true;
}

bool de_byte_node(CByteBlock& root, string name, string& value, uchar index)
{
    CByteBlock* block = root.FindChild(BYTE_SIGN_NODE, name.c_str(), index);

    if(NULL == block) return false;

    value = block->GetBlockValue();

    return true;
}
